#include "Utils.h"
#include "DBlayer.h"
#include <sstream>
#include <algorithm>
#include <libxml/uri.h>
#include <libxml/chvalid.h>
#include <libxml/HTMLparser.h>
#include <libxml/HTMLTree.h>

using namespace std;

void GetContentCharsetFromResponse(const std::string& szResponse, std::string& szCharset)
{
    string szResponseCopy(szResponse);
    _strlwr((char*)szResponseCopy.c_str());
    string::size_type pos = szResponseCopy.rfind("\r\ncontent-type: ");
    if (pos == string::npos)
        return;
    const char* p1 = szResponseCopy.c_str() + pos + strlen("\r\ncontent-type: ");
    const char* p2 = strstr(p1, " charset=");
    if (!p2)
        return;
    p2 += strlen(" charset=");
    while(*p2 && *p2 != ';' && *p2 != ' ' && *p2 != '\r' && *p2 != '\n')
    {
        szCharset += *p2;
        p2++;
    }
}

void GetContentTypeFromResponse(const std::string& szResponse, std::string& szContentType, unsigned int& uiContentType)
{
    string szResponseCopy(szResponse);
    _strlwr((char*)szResponseCopy.c_str());
    string::size_type pos = szResponseCopy.rfind("\r\ncontent-type: ");
    if (pos == string::npos)
    {
        uiContentType = CONTENT_TYPE_UNKNOWN;
        return;
    }
    const char* p = szResponseCopy.c_str() + pos + strlen("\r\ncontent-type: ");
    while(*p && *p != ';' && *p != ' ' && *p != '\r' && *p != '\n')
    {
        szContentType += *p;
        p++;
    }
    if (szContentType == "text/html")
    {
        uiContentType = CONTENT_TYPE_HTML;
    }
    else
    if (szContentType == "application/xml" || szContentType == "text/xml" || szContentType == "application/rss+xml" || szContentType == "application/atom+xml")
    {
        uiContentType = CONTENT_TYPE_XML;
    }
    else
    {
        uiContentType = CONTENT_TYPE_UNKNOWN;
    }
}

void StringToWords(const std::string& szString, const char& separator, std::vector<std::string>& words)
{
    istringstream is(szString);
    string str;
    while(getline(is, str, separator))
        words.push_back(str);        
}

bool IsStringEmpty(const xmlChar* szString)
{
    if (szString)
    {
        int content_len = xmlStrlen(szString);
        int len = content_len;
        int ch = xmlGetUTF8Char(szString, &len);
        while (ch > 0)
        {
            if (xmlIsCharQ(ch) && !xmlIsBlankQ(ch) && ch != 0xa0)
            {   
                return false;
            }
            szString += len;
            content_len -= len;
            len = content_len;
            ch = xmlGetUTF8Char(szString, &len);
        }
    }
    return true;
}

bool IsStringDigits(const xmlChar* szString)
{
    bool bDigitPresent = false;
    if (szString)
    {
        int content_len = xmlStrlen(szString);
        int len = content_len;
        int ch = xmlGetUTF8Char(szString, &len);
        while (ch > 0)
        {
            if (xmlIsBaseCharQ(ch) || xmlIsIdeographicQ(ch))
            {
                return false;
            }
            if (xmlIsDigitQ(ch))
            {
                bDigitPresent = true;
            }
            szString += len;
            content_len -= len;
            len = content_len;
            ch = xmlGetUTF8Char(szString, &len);
        }
        if (bDigitPresent)
            return true;
        else
            return false;
    }
    return false;
}

bool IsBinaryStream(const std::string& szStream)
{
    unsigned int uiOffset = 0;
    while (uiOffset < szStream.size())
    {
        if (szStream[uiOffset] == 0)
            return true;
        uiOffset++;                
    }
    return false;
}

bool IsURLValid(const std::string& szUrl)
{
    xmlURIPtr uri = xmlParseURI(szUrl.c_str());
    if (uri)
    {
        if (uri->server)
        {
            xmlFreeURI(uri);
            return true;
        }        
    }
    return false;
}

void GetDomainNameFormURL(const std::string& szUrl, std::string& szDomainName)
{
    xmlURIPtr uri = xmlParseURI(szUrl.c_str());
    if (uri)
    {
        if (uri->server)
            szDomainName = uri->server;
        xmlFreeURI(uri);
    }
}

void GetGMTDateTime(std::string& szDateTime)
{
    char tmpbuf[128];
    tm *utc;
    time_t t;
    time(&t);
    utc = gmtime(&t);
    strftime(tmpbuf, 128, "%a, %d %b %Y %H:%M:%S GMT", utc);
    szDateTime = tmpbuf;
}

void ReplaceVariables(string& szTemplateText, const VariablesMap& variables)
{
    VariablesMapIter iter;
    for (iter = variables.begin(); iter != variables.end(); iter++)
    {
        unsigned int ulPosition = 0;
        while (ulPosition != string::npos)
        {
            ulPosition = szTemplateText.find(iter->first);
            if (ulPosition != string::npos)
                szTemplateText.replace(ulPosition, strlen(iter->first.c_str()), iter->second);
        }        
    }
}

void ReplaceTemplates(std::string& szTemplateText)
{
    unsigned int ulPositionStart = 0;
    unsigned int ulPositionEnd = 0;

    while (ulPositionStart != string::npos && ulPositionEnd != string::npos)
    {
        ulPositionStart = szTemplateText.find("[#", ulPositionStart);
        if (ulPositionStart != string::npos)
        {
            ulPositionEnd = szTemplateText.find("#]", ulPositionStart+2);
            if (ulPositionEnd != string::npos)
            {
                string szSubject;
                string szNextTemplateText;
                string szDefaultEmailFrom;
                string szDefaultEmailTo;
                string szDefaultEmailCc;
                string szDefaultEmailBcc;
                string szTemplateName(szTemplateText.c_str()+ulPositionStart+2, ulPositionEnd-ulPositionStart-2);
                if (dbLayer->GetEmailTemplate(szTemplateName, szSubject, szNextTemplateText, szDefaultEmailFrom, szDefaultEmailTo, szDefaultEmailCc, szDefaultEmailBcc))
                    szTemplateText.replace(ulPositionStart, ulPositionEnd-ulPositionStart+2, szNextTemplateText);
                else
                    szTemplateText.replace(ulPositionStart, ulPositionEnd-ulPositionStart+2, "template not found");
            }
        }
    }    
}

void GetTextTemplate(xmlNodePtr node, string& szTextTemplate, const bool& bProcessLinks)
{
    xmlNodePtr cur_node = NULL;
    for (cur_node = node; cur_node; cur_node = cur_node->next)
    {
        if (cur_node->type == XML_ELEMENT_NODE && !strcmp((const char*)cur_node->name, "br"))
        {
            szTextTemplate += "\r\n";
        }
        else
        if (cur_node->type == XML_ELEMENT_NODE && !strcmp((const char*)cur_node->name, "p"))
        {
            szTextTemplate += "\r\n\r\n";
        }
        else
        if (cur_node->type == XML_ELEMENT_NODE && bProcessLinks && !strcmp((const char*)cur_node->name, "a"))
        {
            xmlChar* href = xmlGetProp(cur_node, (const xmlChar*)"href");
            if (href)
            {
                string szLinkText;
                GetTextTemplate(cur_node->children, szLinkText, false);
                if (xmlStrcmp(href, (const xmlChar*)szLinkText.c_str()) == 0)
                {
                    szTextTemplate += szLinkText.c_str();
                }
                else
                {
                    szTextTemplate += szLinkText.c_str();
                    szTextTemplate += " ";
                    szTextTemplate += (const char*)href;
                }
                xmlFree(href);
                continue;
            }
        }
        if (xmlNodeIsText(cur_node) && !xmlIsBlankNode(cur_node) && cur_node->content)
        {
            szTextTemplate += (const char*)cur_node->content;
        }
        GetTextTemplate(cur_node->children, szTextTemplate, bProcessLinks);
    }
}

void ConvertTemplateToText(string& szTemplateText)
{
    htmlDocPtr htmlDoc = htmlReadMemory(szTemplateText.c_str(), szTemplateText.size(), NULL, NULL, HTML_PARSE_RECOVER | HTML_PARSE_NOBLANKS | HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING);
    if (htmlDoc)
    {
        string szTextTemplate;
        GetTextTemplate(xmlDocGetRootElement(htmlDoc), szTextTemplate, true);
        if (szTextTemplate.size())
            szTemplateText = szTextTemplate;
        xmlFreeDoc(htmlDoc);
    }
}